package boardgamer.spammer;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;

import java.util.HashSet;

import static com.google.common.base.Preconditions.checkNotNull;

/**
 * @author garysoed
 */
public class AdsPrompt {

  private static final String DISPLAYED_AD_KEY_PREFIX = "spammer_displayed_ad_";
  private static final String SHOW_COUNT_KEY = "spammer_show_count";
  private static final String MARKET_URL_PREFIX = "market://details?id=";

  private static AdsPrompt INSTANCE = null;

  public static void initialize(Activity activity, int showDelayCount) {
    INSTANCE = new AdsPrompt(activity, showDelayCount);
  }

  public static AdsPrompt instance() {
    checkNotNull(INSTANCE, "Cannot get instance before initialization");
    return INSTANCE;
  }

  private final SharedPreferences preferences;
  private final HashSet<AdsType> displayedAds;
  private final ImmutableSet<String> installedPackages;
  private final Activity activity;
  private final int showDelayCount;
  private int showCount;

  private AdsPrompt(Activity activity, int showDelayCount) {
    this.activity = activity;
    this.showDelayCount = showDelayCount;
    this.preferences = activity.getPreferences(Context.MODE_PRIVATE);

    // Load the displayed ads
    this.displayedAds = Sets.newHashSet();
    for (AdsType adsType : AdsType.values()) {
      if (preferences.getBoolean(DISPLAYED_AD_KEY_PREFIX + adsType.name(), false)) {
        displayedAds.add(adsType);
      }
    }

    // Get all installed packages
    PackageManager packageManager = activity.getPackageManager();
    this.installedPackages = ImmutableSet.copyOf(
        Iterables.transform(packageManager.getInstalledPackages(0 /* flags */),
            new Function<PackageInfo, String>() {

              @Override public String apply(PackageInfo input) {
                return input.packageName;
              }
            }));

    this.showCount = preferences.getInt(SHOW_COUNT_KEY, 0);
  }

  public Ads getAds() {
    showCount++;
    if (showCount < showDelayCount) {
      return null;
    }

    Iterable<AdsType> undisplayedAds
        = Iterables.filter(AdsType.ALL_ADS, new Predicate<AdsType>() {
          @Override
          public boolean apply(AdsType input) {
            return !displayedAds.contains(input);
          }
        });

    Iterable<AdsType> adsToDisplay
        = Iterables.filter(undisplayedAds, new Predicate<AdsType>() {
      @Override
      public boolean apply(AdsType input) {
        String packageName = activity.getResources().getString(input.getPackageNameRef());
        return !installedPackages.contains(packageName);
      }
    });

    if (Iterables.isEmpty(adsToDisplay)) {
      return null;
    }
    
    AdsType displayedAd = Iterables.getLast(adsToDisplay);
    displayedAds.add(displayedAd);

    Resources resources = activity.getResources();
    Bitmap logo = BitmapFactory.decodeResource(resources, displayedAd.getLogoRef());
    String promoText = resources.getString(displayedAd.getStringRef());

    Intent marketIntent = new Intent(Intent.ACTION_VIEW);
    marketIntent.setData(
        Uri.parse(MARKET_URL_PREFIX + resources.getString(displayedAd.getPackageNameRef())));
    return new Ads(logo, promoText, marketIntent);
  }

  public void save() {
    SharedPreferences.Editor editor = preferences.edit();
    for (AdsType adsType : displayedAds) {
      editor.putBoolean(DISPLAYED_AD_KEY_PREFIX + adsType.name(), false);
    }
    editor.putInt(SHOW_COUNT_KEY, showCount);
    editor.commit();
  }
}
